package com.ray.tool.net;


import java.net.InetAddress;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 网络编程 - 工具类
 *
 * @author LiaoYuXing-Ray
 * @version 1.0
 * @createDate 2023/8/30 17:28
 **/
public class NetTools {
    /**
     * 工具类中的方法都是静态方法访问的，因此将构造器私有不允许创建对象
     *
     * @author LiaoYuXing-Ray 2023/9/7 10:28
     */
    private NetTools() {
        throw new AssertionError();
    }

    /**
     * IP地址正则表达式 2023/10/21 13:50
     */
    private final static String patternIp = "\\d+\\.\\d+\\.\\d+\\.\\d+";
    /**
     * 定义一个正则表达式模式，用于匹配IP地址
     * 利用好其预编译功能，可以有效加快正则匹配速度
     * 2023/10/21 13:50
     */
    private final static Pattern ip = Pattern.compile(patternIp);
    /**
     * IP地址和端口号正则表达式 2023/10/21 13:51
     */
    private final static String patternIpPort = "\\d+\\.\\d+\\.\\d+\\.\\d+[:]*\\d*";
    /**
     * 定义一个正则表达式模式，用于匹配IP地址和端口号
     * 利用好其预编译功能，可以有效加快正则匹配速度
     * 使用Pattern类的compile方法，将正则表达式编译为Pattern对象
     * 2023/10/21 13:51
     */
    private final static Pattern ipPort = Pattern.compile(patternIpPort);

    /**
     * 获取可访问的服务器URL，首个
     *
     * @param src 服务器地址字符串，多个地址以逗号分隔
     * @return 可访问的服务器URL，如果没有可访问的服务器则返回空字符串
     */
    public static String getServerUrl(String src) {
        String[] str = src.split(",");
        StringBuilder result = new StringBuilder();
        for (String s : str) {
            String ip = getIp(s);
            if (ipCanReach(ip)) {
                result.append(ip).append("\t");
            }
        }

        return result.toString();
    }


    /**
     * 从给定的IP地址字符串中提取IP地址
     *
     * @param src IP地址字符串，格式为x.x.x.x
     * @return 提取到的IP地址，如果未找到匹配的IP地址则返回空字符串
     */
    public static String getIp(String src) {
        Matcher m = ip.matcher(src);
        return m.find() ? m.group() : "";
    }

    /**
     * 从给定的字符串中判断是否含有IP地址
     *
     * @param src 需要判断的可能含有IP地址的字符串，格式为x.x.x.x
     * @return 字符串中是否包含IP地址
     */
    public static boolean isIp(String src) {
        Matcher m = ip.matcher(src);
        return m.find();
    }

    /**
     * 判断字符串是否为有效的IPv4的地址，字符串中不能包含其它字符
     *
     * @param ipv4 需要判断的字符串，格式为x.x.x.x
     * @return 字符串是否为有效的IPv4的地址
     */
    public static boolean isIPv4Address(String ipv4) {
        String regex = "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
        return ipv4.matches(regex);
    }

    /**
     * 判断字符串是否为有效的IPv6的地址，字符串中不能包含其它字符
     *
     * @param ipv6 需要判断的字符串，格式为x.x.x.x
     * @return 字符串是否为有效的IPv6的地址
     */
    public static boolean isIPv6Address(String ipv6) {
        String regex = "^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$";
        return ipv6.matches(regex);
    }

    /**
     * 获取给定字符串中包含的IP地址和端口号。
     *
     * @param src 包含IP地址和端口号的字符串，格式为 "IP:Port"，例如 "192.168.43.4:8080"
     * @return 如果找到匹配的IP地址和端口号，则返回一个字符串，格式为 "IP:Port"，例如 "192.168.43.4:8080"；否则返回空字符串 ""
     */
    public static String getIpPort(String src) {
        // 使用Pattern对象的matcher方法，传入源字符串src，返回一个Matcher对象
        Matcher m = ipPort.matcher(src);
        // 使用Matcher对象的find方法，查找源字符串中是否存在匹配该模式的子串
        // 如果存在，返回该子串（即IP地址和端口号）；如果不存在，返回空字符串
        return m.find() ? m.group() : "";
    }

    /**
     * 从给定的字符串中判断是否包含IP地址和端口号
     *
     * @param src 需要判断的可能包含IP地址和端口号的字符串，格式为 "IP:Port"，例如 "192.168.43.4:8080"
     * @return 字符串中是否包含IP地址和端口号
     */
    public static boolean isIpPort(String src) {
        Matcher m = ipPort.matcher(src);
        return m.find();
    }

    /**
     * 判断字符串是否为有效的端口号，字符串中不能包含其它字符
     *
     * @param port "Port"，例如 "8080"
     * @return 字符串是否为有效的IP地址和端口号
     */
    public static boolean isPort(String port) {
        String regex = "^([0-9]{1,5})$|^([1-9][0-9]{0,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$";
        return port.matches(regex);
    }


    /**
     * 检查给定的IP地址是否可达
     *
     * @param ip IP地址字符串，格式为x.x.x.x
     * @return 如果IP地址可达则返回true，否则返回false
     */
    public static boolean ipCanReach(String ip) {
        return ipCanReach(ip, 3000);
    }

    /**
     * 检查给定的IP地址是否可达，设置超时时间为指定的秒数
     *
     * @param ip      IP地址字符串，格式为x.x.x.x
     * @param timeout 超时时间，单位为秒
     * @return 如果IP地址在指定的超时时间内可达则返回true，否则返回false
     */
    public static boolean ipCanReach(String ip, int timeout) {
        try {
            InetAddress address = InetAddress.getByName(ip);
            return address.isReachable(timeout);
        } catch (Exception var3) {
            return false;
        }
    }

}


